package com.niiwoo.civet.user.service.duboo;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.niiwoo.civet.snapdata.dto.request.SocialSecurityRequestDTO;
import com.niiwoo.civet.snapdata.service.SocialSecurityDataDubboService;
import com.niiwoo.civet.trade.service.configure.TradeConfigDubboService;
import com.niiwoo.civet.trade.service.loan.SpeedLoanDubboService;
import com.niiwoo.civet.user.constants.UserRedisKey;
import com.niiwoo.civet.user.dao.entity.DataStatus;
import com.niiwoo.civet.user.dao.entity.UserBasicInfo;
import com.niiwoo.civet.user.dto.response.ThirdAuthResponseDTO;
import com.niiwoo.civet.user.dto.response.UserAuthorizationInfoResponseDTO;
import com.niiwoo.civet.user.dto.response.UserRealNameInfoDTO;
import com.niiwoo.civet.user.enums.SocialSecurityDataTypeEnum;
import com.niiwoo.civet.user.enums.UserDataStatusEnum;
import com.niiwoo.civet.user.enums.UserDataTypeEnum;
import com.niiwoo.civet.user.enums.UserEnum;
import com.niiwoo.civet.user.service.UserAuthSocialDubboService;
import com.niiwoo.civet.user.service.local.*;
import com.niiwoo.tripod.base.component.PrivacyMasks;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import com.niiwoo.tripod.tiancheng.component.TianchengAuthSocialService;
import com.niiwoo.tripod.tiancheng.request.auth.SocialDataQueryRequest;
import com.niiwoo.tripod.tiancheng.request.auth.ThirdAuthRequest;
import com.niiwoo.tripod.tiancheng.response.auth.SocialDataQueryResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

@Service(version = "1.0.0")
@Slf4j
public class UserAuthSocialDubboServiceImpl implements UserAuthSocialDubboService {

    @Autowired
    private TianchengAuthSocialService tianchengAuthSocialService;

    @Autowired
    private UserDataService userDataService;

    @Autowired
    private UserStatusService userStatusService;

    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;

    @Autowired
    PrivacyMasks privacyMasks;

    @Reference(version = "1.0.0")
    private TradeConfigDubboService tradeConfigDubboService;

    @Reference(version = "1.0.0")
    private SpeedLoanDubboService speedLoanDubboService;

    @Value(value = "${web-http-url}")
    private String webHttpUrl;

    /**
     * 社保回调授权成功通知地址
     */
    private final String SOCIAL_SECURITY_NOTIFY_URL = "/tc/authSocialSecurityNotify/callback";

    /**
     * 社保获取到数据回调地址
     */
    private final String SOCIAL_SECURITY_CALLBACK_URL = "/tc/authSocialSecurityCallback/callback/";

    @Autowired
    private UserAuthCommonService userAuthCommonService;

    @Reference(version = "1.0.0")
    private SocialSecurityDataDubboService socialSecurityDataDubboService;

    @Autowired
    private UserAuthorizationInfoService userAuthorizationInfoService;

    @Autowired
    RedisTemplate<String, String> redisTemplate;

    @Autowired
    private UserBasicInfoService userBasicInfoService;

    /**
     * 获取天秤第三方授权h5页面的url
     *
     * @param userId   用户id
     * @param createIp 用户客户端请求ip
     * @return com.niiwoo.civet.user.dto.response.ThirdAuthResponseDTO
     * @author zzl
     * @date 2017/11/22 16:20
     */
    @Override
    public ThirdAuthResponseDTO getThirdAuthUrl(String userId, String createIp, String city) {

        //获取并判断用户已授权状态
        DataStatus existsUserIdAndType = userStatusService.getByUserIdAndType(userId, UserDataTypeEnum.SOCIAL_SECURITY_OPERATOR_AUTHORIZE);
        Byte dataStatus = null;
        if (existsUserIdAndType != null) {
            dataStatus = existsUserIdAndType.getDataStatus();
            //已授权或已验证，直接返回
            if (UserDataStatusEnum.SocialSecurityStatus.GETSUCCESS.getStatus().equals(existsUserIdAndType.getDataStatus())) {
                ThirdAuthResponseDTO dto = new ThirdAuthResponseDTO();
                //已授权
                dto.setStatus(UserDataStatusEnum.SocialSecurityStatus.GETSUCCESS.getStatus().toString());
                dto.setUserDataStatus(dataStatus);
                return dto;
            }

        }else {
            dataStatus = UserDataStatusEnum.SocialSecurityStatus.NOCREDIT.getStatus();
        }

        //请求天秤获取授权链接
        ThirdAuthResponseDTO dto = userAuthCommonService.getThirdAuthUrl(userId, createIp, tianchengAuthSocialService, webHttpUrl + SOCIAL_SECURITY_NOTIFY_URL, webHttpUrl + SOCIAL_SECURITY_CALLBACK_URL + userId, null, true, city);
        dto.setUserDataStatus(dataStatus);
        return dto;
    }

    /**
     * 查询天秤并保存社保详细信息（天秤数据回调后使用）
     * @author zzl
     * @date 2017/12/11 13:54
     * @param userId 用户id
     * @param socialSecurityAuthCity 社保缴纳城市，天秤方要求不传此参数
     * @param socialSecurityDataTypeEnum 是否融360渠道的调用(调用类型)
     * @return java.lang.Integer
     */
    @Override
    public Integer saveSocialSecurity(String userId, String socialSecurityAuthCity, SocialSecurityDataTypeEnum socialSecurityDataTypeEnum) {

        redisTemplate.opsForSet().add(UserRedisKey.AUTH_SOCIAL_WAIT_QUERY_MAP, userId);
        UserRealNameInfoDTO userRealNameInfoDTO = userDataService.getUserRealNameInfo(userId);
        ThirdAuthRequest request = new ThirdAuthRequest();
        if (userRealNameInfoDTO == null) {
            log.error("保存社保资料时查询用户资料为空,userId:" + userId);
            throw new BizException("USR19078");
        }
        if (StringUtils.isBlank(userRealNameInfoDTO.getRealName())
                || StringUtils.isBlank(userRealNameInfoDTO.getIdCard())) {
            log.error("保存社保资料时查询用户真实姓名为空,userId:" + userId);
            throw new BizException("USR19078");
        }

        if(socialSecurityDataTypeEnum == null){
            UserBasicInfo userBasicInfo = userBasicInfoService.selectUserBasicInfo(userId);
            if(userBasicInfo != null){
                if(UserEnum.RegisterChannel.RONG_360.getValue().equals(userBasicInfo.getRegisterChannel())){
                    socialSecurityDataTypeEnum = SocialSecurityDataTypeEnum.R360_TYPE;
                }else{
                    socialSecurityDataTypeEnum = SocialSecurityDataTypeEnum.SELF_TYPE;
                }
            }
        }

        SocialDataQueryRequest socialDataQueryRequest = new SocialDataQueryRequest();
        socialDataQueryRequest.setTransNo(String.valueOf(snowflakeIdWorker.nextId()));
        socialDataQueryRequest.setIdentityCard(privacyMasks.decryptPrivacy(userRealNameInfoDTO.getIdCard()));
        socialDataQueryRequest.setRealName(userRealNameInfoDTO.getRealName());
        socialDataQueryRequest.setTransDate(new Date());
        socialDataQueryRequest.setDateType(socialSecurityDataTypeEnum.getType());
        CompletableFuture<SocialDataQueryResponse> socialDataQueryResponseCompletableFuture = tianchengAuthSocialService.queryData(socialDataQueryRequest);
        try {
            int timeout = 20;
            SocialDataQueryResponse response = socialDataQueryResponseCompletableFuture.get(timeout, TimeUnit.SECONDS);
            log.info("userId={},社保信息查询天秤返回结果：{}", userId, response);
            if (response == null) {
                throw new BizException("USR19079");
            }

            if (response.getResult_data() == null || "{}".equals(response.getResult_data())) {
                throw new BizException("USR19079");
            }

            SocialSecurityRequestDTO socialSecurityRequestDTO = cover(response);
            if (socialSecurityRequestDTO == null) {
                throw new BizException("USR19081");
            }
            socialSecurityRequestDTO.setUserId(userId);
            Integer result = socialSecurityDataDubboService.saveSocialSecurity(socialSecurityRequestDTO);
            if(result != null){
                if(result > 0){
                    redisTemplate.opsForSet().remove(UserRedisKey.AUTH_SOCIAL_WAIT_QUERY_MAP, userId);
                }else {
                    throw new BizException("USR19082");
                }
            }
            log.info("保存用户社保信息到快照数据库返回结果userId={}, result={}", userId, result);
            return result;
        }  catch (Throwable e) {
            log.error("保存用户社保信息出现异常", e);
        }
        throw new BizException("USR19083");
    }

    private SocialSecurityRequestDTO cover(SocialDataQueryResponse response) {
        SocialSecurityRequestDTO dto = new SocialSecurityRequestDTO();
        dto.setCurrentCity(response.getCurrent_city());
        if (response.getResult_data() == null) {
            return null;
        }

        JSONObject jsonObject = JSONObject.parseObject(response.getResult_data(), JSONObject.class);

        dto.setAccidentInsurance(coverInsuranceList(jsonObject.getJSONArray("accident_insurance")));
        dto.setEndowmentInsurance(coverInsuranceList(jsonObject.getJSONArray("endowment_insurance")));
        dto.setMaternityInsurance(coverInsuranceList(jsonObject.getJSONArray("maternity_insurance")));
        dto.setMedicalInsurance(coverInsuranceList(jsonObject.getJSONArray("medical_insurance")));
        dto.setUnemploymentInsurance(coverInsuranceList(jsonObject.getJSONArray("unemployment_insurance")));

        dto.setMedicalConsumption(coverMedicalConsumptionList(jsonObject.getJSONArray("medical_consumption")));

        dto.setUserInfo(coverUserInfo(jsonObject.getJSONObject("user_info")));
        return dto;
    }

    private SocialSecurityRequestDTO.UserInfo coverUserInfo(JSONObject param) {
        if (param == null) {
            return null;
        }
        SocialSecurityRequestDTO.UserInfo userInfo = new SocialSecurityRequestDTO.UserInfo();
        userInfo.setBeginDate(String.valueOf(param.get("begin_date")));
        userInfo.setCertificateNumber(String.valueOf(param.get("certificate_number")));
        userInfo.setCompanyName(String.valueOf(param.get("company_name")));
        userInfo.setGender(String.valueOf(param.get("gender")));
        userInfo.setHomeAddress(String.valueOf(param.get("home_address")));
        userInfo.setHukouType(String.valueOf(param.get("hukou_type")));
        userInfo.setMobile(String.valueOf(param.get("mobile")));
        userInfo.setName(String.valueOf(param.get("name")));
        userInfo.setNation(String.valueOf(param.get("nation")));
        userInfo.setTimeToWork(String.valueOf(param.get("time_to_work")));
        return userInfo;
    }

    private SocialSecurityRequestDTO.MedicalConsumption coverMedicalConumption(JSONObject param) {
        if (param == null) {
            return null;
        }
        SocialSecurityRequestDTO.MedicalConsumption medicalConsumption = new SocialSecurityRequestDTO.MedicalConsumption();
        medicalConsumption.setBalanceDate(String.valueOf(param.get("balance_date")));
        medicalConsumption.setCashPayment(String.valueOf(param.get("cash_payment")));
        medicalConsumption.setLargeCost(String.valueOf(param.get("large_cost")));
        medicalConsumption.setMedicalInstitution(String.valueOf(param.get("medical_institution")));
        medicalConsumption.setOtherSupport(String.valueOf(param.get("other_support")));
        medicalConsumption.setOverallAccountSpending(String.valueOf(param.get("overall_account_spending")));
        medicalConsumption.setPersonalAccountSpending(String.valueOf(param.get("personal_account_spending")));
        medicalConsumption.setTotalAmount(String.valueOf(param.get("total_amount")));
        medicalConsumption.setType(String.valueOf(param.get("type")));
        return medicalConsumption;
    }

    private List<SocialSecurityRequestDTO.MedicalConsumption> coverMedicalConsumptionList(JSONArray medicalConsumptionList) {
        if (medicalConsumptionList==null || medicalConsumptionList.isEmpty()) {
            return null;
        }
        List<SocialSecurityRequestDTO.MedicalConsumption> responseList = new ArrayList<>();
        Iterator<Object> iterator = medicalConsumptionList.iterator();
        while (iterator.hasNext()) {
            responseList.add(coverMedicalConumption((JSONObject)iterator.next()));
        }
        return responseList;
    }


    private List<SocialSecurityRequestDTO.Insurance> coverInsuranceList(JSONArray jsonArray) {
        if (jsonArray == null || jsonArray.isEmpty()) {
            return null;
        }
        List<SocialSecurityRequestDTO.Insurance> responseList = new ArrayList<>();
        Iterator<Object> it = jsonArray.iterator();
        while (it.hasNext()) {
            JSONObject jsonObject = (JSONObject) it.next();
            responseList.add(coverInsurance(jsonObject));
        }
        return responseList;
    }

    private SocialSecurityRequestDTO.Insurance coverInsurance(JSONObject insurance) {
        SocialSecurityRequestDTO.Insurance queryInsurance = new SocialSecurityRequestDTO.Insurance();
        queryInsurance.setBaseNumber(String.valueOf(insurance.get("base_number")));
        queryInsurance.setCompanyName(String.valueOf(insurance.get("company_name")));
        queryInsurance.setCompanyPercentage(String.valueOf(insurance.get("company_percentage")));
        queryInsurance.setLastPayDate(String.valueOf(insurance.get("last_pay_date")));
        queryInsurance.setMonth(String.valueOf(insurance.get("month")));
        queryInsurance.setMonthCount(String.valueOf(insurance.get("month_count")));
        queryInsurance.setMonthlyCompanyIncome(String.valueOf(insurance.get("monthly_company_income")));
        queryInsurance.setMonthlyPersonalIncome(String.valueOf(insurance.get("monthly_personal_income")));
        queryInsurance.setPersonalPercentage(String.valueOf(insurance.get("personal_percentage")));
        queryInsurance.setStatus(String.valueOf(insurance.get("type")));
        return queryInsurance;
    }

    @Override
    public void saveUserSocialInfo(String userId, String socialSecurityAuthCity, UserDataStatusEnum.SocialSecurityStatus statusEnum, Date authTime) {
        userAuthorizationInfoService.saveUserSocialInfo(userId, socialSecurityAuthCity, statusEnum, authTime, UserDataTypeEnum.SOCIAL_SECURITY_OPERATOR_AUTHORIZE);
    }

    @Override
    public void saveUserSocialInfoForR360(String userId, String socialSecurityAuthCity, UserDataStatusEnum.SocialSecurityStatus statusEnum, Date authTime) {
        userAuthorizationInfoService.saveUserSocialInfo(userId, socialSecurityAuthCity, statusEnum, authTime, UserDataTypeEnum.R360_SOCIAL_SECURITY_OPERATOR_AUTHORIZE);

        RpcContext.getContext().asyncCall(() -> saveSocialSecurity(userId, socialSecurityAuthCity, SocialSecurityDataTypeEnum.R360_TYPE));
    }

    /**
     * 神盾后台刷新同步天秤的用户社保信息
     *
     * @param userId 用户id
     * @return
     * @author zzl
     * @date 2018/1/15 16:41
     */
    @Override
    public void refreshSocialSecurity(String userId) {
        DataStatus existsUserIdAndType = userStatusService.getByUserIdAndType(userId, UserDataTypeEnum.SOCIAL_SECURITY_OPERATOR_AUTHORIZE);
        if(existsUserIdAndType == null){
            throw new BizException("USR19084");
        }
        if(!UserDataStatusEnum.SocialSecurityStatus.GETSUCCESS.getStatus().equals(existsUserIdAndType.getDataStatus())){
            throw new BizException("USR19084");
        }
        this.saveSocialSecurity(userId, null,null);
    }

}
